import 'dart:convert';

import 'package:aichat_flutter_wallet/module/module_browser/provider/browser_proviser.dart';
import 'package:aichat_flutter_wallet/module/module_browser/widget/connect_account.dart';
import 'package:aichat_flutter_wallet/module/module_browser/widget/dapp_add_token.dart';
import 'package:aichat_flutter_wallet/module/module_browser/widget/dapp_invoke_contract.dart';
import 'package:aichat_flutter_wallet/module/module_browser/widget/dapp_modal_tips.dart';
import 'package:aichat_flutter_wallet/module/module_browser/widget/dapp_token_transfer.dart';
import 'package:aichat_flutter_wallet/module/module_browser/widget/select_network.dart';
import 'package:aichat_flutter_wallet/module/module_browser/widget/sign.dart';
import 'package:aichat_flutter_wallet/module/module_wallet/provider/wallet_node_provider.dart';
import 'package:aichat_flutter_wallet/module_common/network/chains_type/ethchain.dart';
import 'package:aichat_flutter_wallet/module_common/provider/nav_key.dart';
import 'package:aichat_flutter_wallet/module_common/provider/token_list_provider.dart';
import 'package:aichat_flutter_wallet/module_common/provider/user_settings_provider.dart';
import 'package:aichat_flutter_wallet/module_common/provider/wallet_info_provider.dart';
import 'package:aichat_flutter_wallet/module_common/utils/sign.dart';
import 'package:aichat_flutter_wallet/module_common/utils/auth.dart';
import 'package:aichat_flutter_wallet/module_common/utils/util.dart';
import 'package:aichat_flutter_wallet/module_common/widgets/dialog/dialog_utils.dart';
import 'package:encrypt/encrypt.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:lib_database/lib_database.dart';
import 'package:lib_util/lib_util.dart';
import 'package:lib_web3/lib_web3.dart';

import '../../../kai_print.dart';

class Web3MethodCall {
  static late InAppWebViewController webViewController;
  static late Chain chain;
  static late WalletInfo walletInfo;

  // 单例模式
  Web3MethodCall._(InAppWebViewController controller) {
    webViewController = controller;
  }

  factory Web3MethodCall(InAppWebViewController controller) {
    return Web3MethodCall._(controller);
  }

// 执行回调
  checkMethodCall(String arg) {
    String method = jsonDecode(arg)['name'];
    String network = jsonDecode(arg)['network'];
    int id = jsonDecode(arg)['id'];
    dynamic data = jsonDecode(arg)['object'];
    if (method == 'requestAccounts') {
      eth_requestAccounts(network: network, method: method, id: id);
    } else if (method == 'switchEthereumChain') {
      eth_switchEthereumChain(id: id, chainId: data['chainId']);
    } else if (method == 'signMessage') {
      String err = "eth_sign has been disabled. You must enable it in the advanced settings";
      String js = 'window.ethereum.sendError($id,"${err}");';
      webViewController.evaluateJavascript(source: js);
    }
    // 签名
    else if (method == 'signPersonalMessage') {
      String message = data['data'];
      String messageDecode = '';
      if (message.startsWith('0x')) {
        message = message.substring(2);
      }
      try {
        messageDecode = utf8.decode(decodeHexString(message));
      } catch (e) {
        Config.logger.e(e);
        messageDecode = message;
      }
      eth_signPersonalMessage(id, messageDecode, data['data']);
    }
    // 签名数据
    else if (method == 'signTypedMessage') {
      String err = "Not supported yet";
      String js = 'window.ethereum.sendError($id,"${err}");';
      webViewController.evaluateJavascript(source: js);
    }
    // // 主币转账
    else if (method == 'signTransaction' && (data['data'] == '' || data['data'] == null || data['data'] == '0x')) {
      transferMain(id, data, transType: TransDialog.TransferDialog);
    }
    //合约转账
    else if (method == 'signTransaction' &&
        data['data'].substring(0, 10) == '0xa9059cbb' &&
        data['data'].length == 138) {
      transferMain(id, data, transType: TransDialog.TransferDialog);
    }
    //合约授权
    else if (method == 'signTransaction' &&
        data['data'].substring(0, 10) == '0x095ea7b3' &&
        data['data'].length == 138) {
      transferMain(id, data, transType: TransDialog.AuthDialog);
    }
    //合约调起
    else if (method == 'signTransaction' && data['data'] != '') {
      transferMain(id, data, transType: TransDialog.InVokeDialog);
    } else if (method == 'watchAsset') {
      // 添加代币
      eth_watchAsset(data, id);
    }
  }

  eth_watchAsset(Map<String, dynamic> data, int id) {
    int decimals = data['decimals'];
    String symbol = data['symbol'];
    String contract = data['contract'];
    BuildContext context = NavKey.getContext();
    showModalBottomSheet(
        context: context,
        backgroundColor: Colors.transparent,
        isScrollControlled: true,
        builder: (_) {
          return DappAddTokenWidget(decimals: decimals.toString(), symbol: symbol, contract: contract);
        }).then((value) {
      if (value == null || !value) return;
      // 是否添加过
      Token? isExist = ObjectBox()
          .tokenModel
          .getTokenByWalletInfoIdAndTokenContract(context.read<TokenListNotifier>().walletInfoId, contract);

      if (isExist != null) {
        context.read<TokenListNotifier>().deleteTokens(isExist);
        DialogUtils.showToast(message: 'The token address already exists', status: "0");
        Map<String, dynamic> err = {"code": 4001, "message": "The token address already exists."};
        String js = 'window.ethereum.sendError($id,"${err}");';
        webViewController.evaluateJavascript(source: js);
        return;
      } else {
        Token item = Token(
            walletInfoId: context.read<TokenListNotifier>().walletInfoId,
            contractType: TokenType.token20.name,
            contract: contract,
            name: symbol,
            symbol: symbol,
            decimals: decimals,
            balance: '0.00',
            valueusd: '0.00',
            change24h: '0.00',
            enable: true,
            isAdded: true,
            isCustom: true);
        context.read<TokenListNotifier>().addCustomTokens(item);
        String js = 'window.ethereum.sendResponse($id,"true");';
        webViewController.evaluateJavascript(source: js);
      }
    });
  }

  // 连接钱包
  eth_requestAccounts({required int id, required String network, required String method}) {
    // Wallet wallet =
    Wallet? wallet = NavKey.getContext().read<WalletInfoNotifier>().wallet;
    kaiPrint('wallet===${wallet}');
    if (wallet == null) {
      DialogUtils.showDialogModal(child: DappModalTipsWidget(tips: 'No wallet found. Please create a wallet!'))
          .then((value) {
        kaiPrint('object-----${value}');
      });
    } else {
      bool isConnet = NavKey.getContext().read<BrowserProvider>().isConnectWallet;
      String address = NavKey.getContext().read<WalletInfoNotifier>().walletAddress;
      if (isConnet) {
        String js = 'window.$network.setAddress("${address}");'
            // 'console.log(window.ethereum);'
            'window.$network.sendResponse($id,["${address}"]);';
        webViewController.evaluateJavascript(source: js);
      } else {
        showModalBottomSheet(
            context: NavKey.getContext(),
            backgroundColor: Colors.transparent,
            isScrollControlled: true,
            builder: (_) {
              return ConnectAccount(
                title: 'Connect Account',
                address: address,
                walletName: wallet.name!,
                onConfrim: (value) {
                  Navigator.of(NavKey.getContext()).pop(true);
                },
              );
            }).then((value) {
          if (value) {
            String js = 'window.$network.setAddress("${address}");'
                // 'console.log(window.ethereum);'
                'window.$network.sendResponse($id,["${address}"]);';
            webViewController.evaluateJavascript(source: js);
            NavKey.getContext().read<BrowserProvider>().setWalletConnect(true);
          }
        });
      }
    }
  }

  Map<String, dynamic> updateTransferData(Map<String, dynamic> obj) {
    try {
      if (obj['gas'] != null) {
        obj['gas'] = obj['gas'].startsWith('0x')
            ? int.parse(obj['gas']).toString()
            : int.parse(obj['gas'], radix: 16).toString();
      }
      if (obj['gasPrice'] != null) {
        obj['gasPrice'] = obj['gasPrice'].startsWith('0x')
            ? (int.parse(obj['gasPrice'])).toString()
            : int.parse(obj['gasPrice'], radix: 16).toString();
      }
      if (obj['nonce'] != null) {
        obj['nonce'] = obj['nonce'].startsWith('0x') ? int.parse(obj['nonce']) : int.parse(obj['nonce'], radix: 16);
      }
      if (obj['value'] != null) {
        obj['value'] = obj['value'].startsWith('0x')
            ? int.parse(obj['value']).toString()
            : int.parse(obj['value'], radix: 16).toString();
      }
      return obj;
    } catch (e) {
      return obj;
    }
  }

  // 主币转账
  transferMain(id, transferData, {TransDialog? transType}) {
    Map<String, dynamic> obj = transferData;
    obj = updateTransferData(obj);
    String from = obj['from'];
    String to = obj['to'];
    String? value = obj['value'];
    String? gasPrice = obj['gasPrice'];
    String? gas = obj['gas'];
    String? data = obj['data'];
    int? nonce = obj['nonce'];
    ETHTransaction transaction =
        ETHTransaction(from: from, to: to, value: value, gas: gas, gasPrice: gasPrice, data: data, nonce: nonce);
    // List<Chain> chainList = getNetworkList();
    // Chain chain = chainList.firstWhere((element) {
    //   return element.evmInfo!.chainId == 97;
    // });
    Chain? chain = NavKey.getContext().read<BrowserProvider>().selectChain;
    showModalBottomSheet(
        context: NavKey.getContext(),
        backgroundColor: Colors.transparent,
        isScrollControlled: true,
        builder: (_) {
          return TokenTransferWidget(chain: chain!, transactionBean: transaction, dialogType: transType);
        }).then((value) {
      if (value == null) {
        Map<String, dynamic> err = {"code": 4001, "message": "Kai Tx Signature: User denied transaction signature."};
        String js = 'window.ethereum.sendError($id,"${err}");';
        webViewController.evaluateJavascript(source: js);
      } else {
        Sign.EthSgin(value['ethTransaction'], chain!, status: transType == TransDialog.TransferDialog,
            successCallback: (val) {
          Log.logger.e(val);
          String js = 'window.ethereum.sendResponse($id,"${val}");';
          webViewController.evaluateJavascript(source: js);
          value['callback']?.call(val);
        }, errCallback: (e) {
          Log.logger.e(e);
          String js = 'window.ethereum.sendError($id,"${e}");';
          webViewController.evaluateJavascript(source: js);
        });
      }
    });
  }

  // 连接前修改配置和节点
  static changeNetConfig({required int chainId, required String nodeUrl}) {
    InAppWebViewController? controller = NavKey.getContext().read<BrowserProvider>().webViewController;
    if (controller != null) {
      String js =
          'window.ethereum.setConfig({ethereum:{chainId: ${chainId},rpcUrl:"${nodeUrl}"},solana:{cluster:"mainnet-beta"},isDebug:true});'
          "window.ethereum.ready=true;";
      controller.evaluateJavascript(source: js);
      NavKey.getContext().read<BrowserProvider>().switchChainNet(chainIdOx: chainId.toString(), needChangeOx: false);
    }
  }

  // 触发切换网络
  eth_switchEthereumChain({required int id, required String chainId}) {
    if (!checkIsSupport(chainId)) {
      showModalBottomSheet(
          context: NavKey.getContext(),
          backgroundColor: Colors.transparent,
          isScrollControlled: true,
          builder: (_) {
            return DappModalTipsWidget(
              tips: 'The current wallet does not support switching to the network',
            );
          });
    } else {
      String nodeUrl = '';
      String address = NavKey.getContext().read<WalletInfoNotifier>().walletAddress;
      nodeUrl = matchNetAndNode(chainId: chainId);
      String js =
          'window.ethereum.setConfig({ethereum:{chainId: ${chainId},rpcUrl:"${nodeUrl}"},solana:{cluster:"mainnet-beta"},isDebug:true});'
          'window.ethereum.address="${address}";'
          "window.ethereum.ready=true;"
          "console.log(111,window.ethereum);"
          "window.ethereum.emitChainChanged(${chainId});"
          'window.ethereum.sendResponse($id,["${address}"]);';
      webViewController.evaluateJavascript(source: js);
      NavKey.getContext().read<BrowserProvider>().switchChainNet(chainIdOx: chainId);
    }
  }

  //  搜索栏切换网络
  static changeNetwork({required int chainId, required String nodeUrl}) async {
    // chainId = 89;
    // NavKey.getContext().read<BrowserProvider>().reload();
    String hexadecimalNumber = '0x' + chainId.toRadixString(16);

    String address = NavKey.getContext().read<WalletInfoNotifier>().walletAddress;
    String js =
        'window.ethereum.setConfig({ethereum:{chainId: ${hexadecimalNumber},rpcUrl:"${nodeUrl}"},solana:{cluster:"mainnet-beta"},isDebug:true});'
        'window.ethereum.address="${address}";'
        "window.ethereum.ready=true;"
        "console.log(11,window.ethereum);"
        "window.ethereum.emitChainChanged('${hexadecimalNumber}')";
    // "window.ethereum.emitConnect();";
    webViewController.evaluateJavascript(source: js);
  }

//  签名
  eth_signPersonalMessage(id, message, sign) {
    showModalBottomSheet(
        context: NavKey.getContext(),
        backgroundColor: Colors.transparent,
        isScrollControlled: true,
        builder: (_) {
          return Signature(
            sign: message,
          );
        }).then((value) {
      if (value == null) {
        Map<String, dynamic> err = {"code": 4001, "message": "Kai Tx Signature: User denied transaction signature."};
        String js = 'window.ethereum.sendError($id,"${err}");';
        webViewController.evaluateJavascript(source: js);
      } else {
        Sign.EthSginData(sign, successCallback: (val) {
          Log.logger.e(val);
          String js = 'window.ethereum.sendResponse($id,"${val}");';
          webViewController.evaluateJavascript(source: js);
        }, errCallback: (e) {
          Log.logger.e(e);
          String js = 'window.ethereum.sendError($id,"${e}");';
          webViewController.evaluateJavascript(source: js);
        });
      }
    });
  }

  // 选择网络弹窗
  static Future selectNetwork({Widget? child}) {
    return showModalBottomSheet(
        context: NavKey.getContext(),
        backgroundColor: Colors.transparent,
        isScrollControlled: true,
        builder: (_) {
          return child == null ? SelectNetwork(title: 'Select Network and Wallet') : child;
        });
  }

  // 触发转账
  eth_signTransaction({required Map<String, dynamic> data}) {
    return showModalBottomSheet(
        context: NavKey.getContext(),
        backgroundColor: Colors.transparent,
        isScrollControlled: true,
        builder: (_) {
          return DappInvokeContractWidget(transationInfo: data);
        }).then((value) {
      if (value == null) {
      } else {
        // 验证密码
        // checkPassword();
      }
    });
  }

  // 判断当前网络是否之前
  static bool checkIsSupport(String chainIdOx) {
    int chainId = NavKey.getContext().read<BrowserProvider>().hexToDecimal(chainIdOx);
    List<Chain> list = getNetworkList();
    if (list.isNotEmpty) {
      var resList = list.map((e) {
        return e.evmInfo!.chainId;
      });
      if (resList.contains(chainId)) {
        return true;
      } else {
        return false;
      }
    }
    return false;
  }

  // 匹配网络和节点
  static String matchNetAndNode({required String chainId}) {
    int num = hexToDecimal(chainId);
    List<Chain> chainList = getNetworkList();
    Chain chain = chainList.firstWhere((element) {
      return element.evmInfo!.chainId == num;
    });
    NodeInfo nodeInfoData = ObjectBox().nodeInfoModel.getSelectedNodeInfo(chain.shortName);
    return nodeInfoData.url;
  }

  // 16进制转为10进制
  static int hexToDecimal(String hex) {
    int decimal = int.parse(hex);
    return decimal;
  }

  static List<Chain> getNetworkList() {
    List<Chain> _chains = [];
    Wallet? wallet = NavKey.getContext().read<WalletInfoNotifier>().wallet;
    if (wallet != null) {
      List<WalletInfo> infos = ObjectBox().walletInfoModel.getWalletInfoListByWalletId(wallet.id);
      for (var w in infos) {
        Chain? c = w.getChain();
        if (null != c) {
          _chains.add(c);
        }
      }
    }
    return _chains;
  }

// 获取节点
  static List<NodeInfo> getNodeList(String name) {
    List<NodeInfo> list = NavKey.getContext().read<NodeProvider>().nodeInfoList(chain: name);
    return list;
  }

// 区块高度
  static Future<Map<String, dynamic>> getBlockHeight(String url) async {
    String _blockHeight = '';
    Color _currentColor = NodeRateUtils.errorColor;
    int _currentRate = 0;
    try {
      //这里记录时间
      final startTime = DateTime.now();
      var res = await FlutterWeb3.getERC20BlockHeightByRpc(url);
      //这里结束时间
      final endTime = DateTime.now();
      _currentRate = endTime.difference(startTime).inMilliseconds;
      if (_currentRate == 0) {
        _currentColor = NodeRateUtils.errorColor;
      }
      if (_currentRate > 0) {
        _currentColor = NodeRateUtils.fastColor;
      }
      if (_currentRate >= 300) {
        _currentColor = NodeRateUtils.mediumColor;
      }
      if (_currentRate >= 1000) {
        _currentColor = NodeRateUtils.slowColor;
      }
      _blockHeight = res.toString();
    } catch (e) {
      print('${e}');
    }
    Map<String, dynamic> resMap = {};
    resMap['height'] = _blockHeight;
    resMap['color'] = _currentColor;
    resMap['rate'] = _currentRate;
    return resMap;
  }

  // 简写地址
  static String thumAddress({String? address}) {
    if (address == null) return '';
    if (address.isEmpty) return address;
    if (address.length > 10) {
      String str1 = address.substring(0, 5);
      String str2 = address.substring(address.length - 5);
      return str1 + '...' + str2;
    }
    return address;
  }

  // 检测密码
  static Future checkPassword({Function? passBack, Function? failBack, bool showToast = true}) async {
    BuildContext context = NavKey.getContext();
    bool isSetPass = await context.read<UserSettingsProvider>().hasPassword();
    if (isSetPass) {
      bool pass = await Authentication().startLocalAuth(
          showPasswordError: false,
          callBackError: () {
            DialogUtils.showToast(message: 'Verification password error', status: "0");
          });
      if (!pass) {
        if (failBack != null) {
          failBack();
        }
        return Future.value(false);
      }
      if (pass) {
        if (passBack != null) {
          passBack();
        }
        return Future.value(true);
      }
    } else {
      return showModalBottomSheet(
          context: NavKey.getContext(),
          backgroundColor: Colors.transparent,
          isScrollControlled: true,
          builder: (_) {
            return DappModalTipsWidget(
              tips: 'There is currently no password set, please go to the wallet management center to set a password!',
            );
          }).then((value) {
        return Future.value(false);
      }).catchError((e) {
        return Future.value(false);
      });
    }
  }
}
